package com.wft.design.system.service.impl;

import com.wft.design.common.core.constant.GlobalCacheKey;
import com.wft.design.common.mybatis.service.impl.BaseServiceImpl;
import com.wft.design.system.channel.DynamicRouteChannel;
import com.wft.design.system.entity.SysGatewayRoute;
import com.wft.design.system.mapper.SysGatewayRouteMapper;
import com.wft.design.system.service.SysGatewayRouteService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author WFT
 * @date 2020/2/5
 * description:
 */
@Service
@RequiredArgsConstructor
public class SysGatewayRouteServiceImpl extends BaseServiceImpl<SysGatewayRouteMapper, SysGatewayRoute>
        implements SysGatewayRouteService {

    private final RedisTemplate<Object,Object> redisTemplate;
    private final DynamicRouteChannel routeChannel;

    @Override
    public Collection<SysGatewayRoute> selectRoutes() {
        //  从缓存中获取所有路由配置
        HashOperations<Object, Object, Object> operations = this.redisTemplate.opsForHash();
        Map<Object, Object> routeMap = operations.entries(GlobalCacheKey.GATEWAY_ROUTE);
        if (routeMap.isEmpty()){
            //  查询数据库
            List<SysGatewayRoute> routeList = this.list();
            //  若数据库中存在数据,则加入缓存
            if (!routeList.isEmpty()){
                routeList.forEach(route -> routeMap.put(String.valueOf(route.getId()),route));
                operations.putAll(GlobalCacheKey.GATEWAY_ROUTE,routeMap);
            }
            return routeList;
        }
        //  将缓存中的数据直接返回
        List<SysGatewayRoute> routeList = new ArrayList<>(routeMap.size());
        routeMap.values().forEach(obj -> routeList.add((SysGatewayRoute) obj));
        return routeList;
    }

    /**
     * 通知网关更新路由信息
     * @param route com.wft.design.system.entity.SysGatewayRoute
     */
    private void syncGatewayRoute(SysGatewayRoute route){
        //  替换缓存中的数据
        this.redisTemplate.opsForHash().put(GlobalCacheKey.GATEWAY_ROUTE,String.valueOf(route.getId()),route);
        Message<SysGatewayRoute> message = MessageBuilder.withPayload(route)
                .setHeader("method", "edit")
                .build();
        this.routeChannel.output().send(message);
    }

    @Override
    public void createRoute(SysGatewayRoute route) {
        //  设置创建/修改时间
        LocalDateTime now = LocalDateTime.now();
        route.setCreateTime(now);
        route.setLastModifyTime(now);
        //  保存路由记录,并异步通知网关更新路由信息
        this.save(route);
        this.syncGatewayRoute(route);
    }

    @Override
    public void deleteById(String routeId) {
        //  删除数据库中的记录
        if (this.removeById(routeId)){
            //  删除缓存
            this.redisTemplate.opsForHash().delete(GlobalCacheKey.GATEWAY_ROUTE,routeId);
            //  通知网关删除此路由配置
            Message<String> message = MessageBuilder.withPayload(routeId)
                    .setHeader("method", "delete")
                    .build();
            this.routeChannel.output().send(message);
        }
    }

    @Override
    public SysGatewayRoute selectById(String routeId) {
        Object obj = this.redisTemplate.opsForHash().get(GlobalCacheKey.GATEWAY_ROUTE, routeId);
        return null == obj ? null : (SysGatewayRoute) obj;
    }

    @Override
    public void updateRoute(SysGatewayRoute route) {
        //  获取路由信息
        SysGatewayRoute dbRoute = this.selectById(route.getId().toString());
        Assert.notNull(dbRoute,"路由Id不存在");
        //  设置创建/修改时间
        route.setCreateTime(dbRoute.getCreateTime());
        route.setLastModifyTime(LocalDateTime.now());
        //  修改数据库数据后通知网关更新路由信息
        if (this.updateById(route)) {
            this.syncGatewayRoute(route);
        }
    }
}
